/*
 * @(#)FraserFunction.java
 *
 * Revision:
 * Author                                         Date           
 * --------------------------------------------   ------------   
 * Ana Emilia Victor Barbosa Coutinho             25/06/2012    
 */
package br.edu.ufcg.splab.techniques.reduction.functions.similarity;

import br.edu.ufcg.splab.core.InterfaceEdge;
import br.edu.ufcg.splab.core.InterfaceVertex;
import br.edu.ufcg.splab.core.graph.Tree;
import br.edu.ufcg.splab.generator.TestCase;
import br.edu.ufcg.splab.generator.TestSuite;
import br.edu.ufcg.splab.techniques.converter.ConvertTestSuiteToTree;

public class FraserFunction implements DistanceFunction {

	/**
	 * Returns the value of redundancy between two test cases (this test cases as a tree).  
	 * The redundancy of the tree is the ratio of the sum of the redundancy values R 
	 * for the children of the root-node and the number of arcs in the tree.
	 * 
	 * @param path1 First test case.
	 * @param path2 Second test case.
	 * @return The similarity degree between two test cases.
	 */
	public double getSimilarity(TestCase path1, TestCase path2){
		TestSuite ts = new TestSuite();
		ts.add(path1);
		ts.add(path2);
		
		//Converter from test suite to tree.
		ConvertTestSuiteToTree conv = new ConvertTestSuiteToTree(ts);
		Tree tree = conv.getTree();	
		return getRedundancy(tree);		
	}

	/**
     * Provide a string representation of the similarity function to be written.
     * @return The string representation of the similarity function.
     */
	public String getFunctionName(){
		return "Fraser";
	}

	/*
	 * Fraser, G. and Wotawa, F. (2007). Redundancy based test-suite reduction. 
	 * In Proceedings of the 10th international conference on Fundamental approaches 
	 * to software engineering, FASE07, pages 291305, Berlin, Heidelberg. Springer-Verlag.
	 */
	private double getRedundancy(Tree tree){		
		double r = getSumRedundancy(tree.getRoot());
		return (1.00/(tree.getEdges().size())) * r;
	}
	
	/*
	 * Sum the redundancy values for the children of the root-node.
	 */
	private double getSumRedundancy(InterfaceVertex node){
		double sum = 0;
		if(!node.getOutTransitions().isEmpty()){
			for(InterfaceEdge children:node.getOutTransitions()){
				sum = sum + getTreeNodeRedundancy(children.getTo());;
			}
			return sum;
		}
		return 0.00;
	}
	
	/*
	 * Calculates the redundancy value for the children of the node.
	 * Returns 0.00 if the node not have children.
	 */
	private double getTreeNodeRedundancy(InterfaceVertex node){
		double nodeRedundancy = 0.00;
		if(!node.getOutTransitions().isEmpty()){
			nodeRedundancy = Math.abs(node.getOutTransitions().size() - 1);
			for(InterfaceEdge children:node.getOutTransitions()){
				nodeRedundancy = nodeRedundancy + getTreeNodeRedundancy(children.getTo());
			}			
			return nodeRedundancy;
		}
		return nodeRedundancy;
	}	

}
